﻿Imports OpenTK
Imports OpenTK.Graphics.OpenGL

Public Class TransformFeedback

    Dim test() As Single =
        {4, 3, 2, 1, 4, 3, 2, 1, 4, 3, 2, 1,
        6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4,
        7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9}

    '不带其它信息的三角形数据
    Public Sub New(trianglesdata() As Single)

        vertices = trianglesdata
        'vertices = test
        BufferSize = vertices.Length * 4
        CreateBufferObject()
    End Sub

    Private size As Integer
    Public Property BufferSize As Integer
        Get
            Return size
        End Get
        Private Set(value As Integer)
            size = value
        End Set
    End Property

    Public vbo As Integer
    Public tfboPosition As Integer
    Public tfboNormal As Integer
    Public tfboTexcoord As Integer
    Private vertices() As Single


    Public mappedPosition As IntPtr
    Public mappedNormal As IntPtr
    Public mappedTexcoord As IntPtr
    Private Sub CreateBufferObject()
        vbo = GL.GenBuffer()
        GL.BindBuffer(BufferTarget.ArrayBuffer, vbo)
        GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * 4, vertices, BufferUsageHint.StaticDraw)
        GL.BindBuffer(BufferTarget.ArrayBuffer, 0)

        tfboPosition = GL.GenBuffer() 'newPosition
        GL.BindBuffer(BufferTarget.TransformFeedbackBuffer, tfboPosition)
        GL.BufferData(BufferTarget.TransformFeedbackBuffer, vertices.Length * 4 / 3, IntPtr.Zero, BufferUsageHint.StaticRead)
        'GL.BufferStorage(BufferTarget.TransformFeedbackBuffer, vertices.Length * 4 / 3, IntPtr.Zero, BufferStorageFlags.MapPersistentBit Or BufferStorageFlags.MapCoherentBit Or BufferStorageFlags.MapReadBit)
        GL.BindBuffer(BufferTarget.TransformFeedbackBuffer, 0)

        tfboNormal = GL.GenBuffer() 'newNormal
        GL.BindBuffer(BufferTarget.TransformFeedbackBuffer, tfboNormal)
        GL.BufferData(BufferTarget.TransformFeedbackBuffer, vertices.Length * 4 / 3, IntPtr.Zero, BufferUsageHint.StaticRead)
        'GL.BufferStorage(BufferTarget.TransformFeedbackBuffer, vertices.Length * 4 / 3, IntPtr.Zero, BufferStorageFlags.MapPersistentBit Or BufferStorageFlags.MapCoherentBit Or BufferStorageFlags.MapReadBit)
        GL.BindBuffer(BufferTarget.TransformFeedbackBuffer, 0)

        tfboTexcoord = GL.GenBuffer() 'newTexcoord
        GL.BindBuffer(BufferTarget.TransformFeedbackBuffer, tfboTexcoord)
        GL.BufferData(BufferTarget.TransformFeedbackBuffer, vertices.Length * 4 / 3, IntPtr.Zero, BufferUsageHint.StaticRead)
        'GL.BufferStorage(BufferTarget.TransformFeedbackBuffer, vertices.Length * 4 / 3, IntPtr.Zero, BufferStorageFlags.MapPersistentBit Or BufferStorageFlags.MapCoherentBit Or BufferStorageFlags.MapReadBit)
        GL.BindBuffer(BufferTarget.TransformFeedbackBuffer, 0)

    End Sub

    Public Sub Enable()

        Dim outs() As String = {"newPosition", "newNormal", "newTexcoord"}
        Dim program = ShaderManager.Find("Feedback")
        GL.TransformFeedbackVaryings(program,
                                     3, outs, TransformFeedbackMode.SeparateAttribs)
        GL.LinkProgram(program)
        GL.UseProgram(program)

        GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, 0, tfboPosition)
        GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, 1, tfboNormal)
        GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, 2, tfboTexcoord)
        'GL.BindBuffersBase(BufferRangeTarget.TransformFeedbackBuffer, 0, 3, {tfbo, tfbo2, tfbo3})

        GL.Enable(EnableCap.RasterizerDiscard)
        GL.BeginTransformFeedback(TransformFeedbackPrimitiveType.Points)

    End Sub

    Public Sub Draw(mtx As Matrix4)

        GL.BindBuffer(BufferTarget.ArrayBuffer, vbo)
        Dim stride As Integer = vertices.Length * 4 \ 3 REM position normal texcoord
        GL.EnableVertexAttribArray(0)
        GL.EnableVertexAttribArray(1)
        GL.EnableVertexAttribArray(2)
        GL.VertexAttribPointer(0, 4, VertexAttribPointerType.Float, False, 0, 0)
        GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, False, 0, stride)
        GL.VertexAttribPointer(2, 4, VertexAttribPointerType.Float, False, 0, stride * 2)

        Dim program As Integer = ShaderManager.Active("Feedback")
        Dim uModel As Integer = GL.GetUniformLocation(program, "Model")

        GL.UniformMatrix4(uModel, False, mtx)
        GL.DrawArrays(PrimitiveType.Points, 0, vertices.Length \ 4 \ 3)
        GL.BindBuffer(BufferTarget.ArrayBuffer, 0)
    End Sub

    Public Sub Disable()
        GL.EndTransformFeedback()
        GL.Flush()
        GL.Disable(EnableCap.RasterizerDiscard)
    End Sub

    Public Sub CopyFeedbackDataToOutput(bufferOutput As Integer)
        Dim stride As Integer = vertices.Length * 4 \ 3
        GL.BindBuffer(BufferTarget.ArrayBuffer, bufferOutput)

        GL.BindBuffer(BufferTarget.TransformFeedbackBuffer, tfboPosition)
        GL.CopyBufferSubData(BufferTarget.TransformFeedbackBuffer, BufferTarget.ArrayBuffer, IntPtr.Zero, 0, stride)
        GL.BindBuffer(BufferTarget.TransformFeedbackBuffer, tfboNormal)
        GL.CopyBufferSubData(BufferTarget.TransformFeedbackBuffer, BufferTarget.ArrayBuffer, IntPtr.Zero, stride, stride)
        GL.BindBuffer(BufferTarget.TransformFeedbackBuffer, tfboTexcoord)
        GL.CopyBufferSubData(BufferTarget.TransformFeedbackBuffer, BufferTarget.ArrayBuffer, IntPtr.Zero, stride * 2, stride)
        GL.BindBuffer(BufferTarget.ArrayBuffer, 0)
    End Sub
End Class
